package com.fang.system.rpc.proxy;

import com.fang.system.rpc.callback.ResponseMappingCallback;
import com.fang.system.rpc.model.MyContent;
import com.fang.system.rpc.model.MyHeader;
import com.fang.system.rpc.model.PackageMsg;
import com.fang.system.rpc.pool.ClientFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * @author fanglingxiao
 * @createDateTime 2022/7/16 5:06 下午
 */
public class ProxyFactory {

    public static <T> T proxyGet(Class<T> clazz) {
        ClassLoader loader = clazz.getClassLoader();
        return (T) Proxy.newProxyInstance(loader, new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // consumer对provider调用过程
                // 1.对于服务、方法、参数 => 封装成message
                MyContent content = convertContent(clazz, method, args);
                //
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                ObjectOutputStream objectStream = new ObjectOutputStream(out);
                objectStream.writeObject(content);
                byte[] msgBody = out.toByteArray();
                // 组装请求头
                MyHeader header = convertHeader(msgBody);
                // 组装package
                out.reset();
                PackageMsg packageMsg = new PackageMsg(header,content);
                objectStream = new ObjectOutputStream(out);
                objectStream.writeObject(packageMsg);
                byte[] packageMsgByte = out.toByteArray();

                // 连接池 获取client
                InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9090);
                NioSocketChannel client = ClientFactory.getInstance().getClient(address);

                // 发送 =>netty
                ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer(packageMsgByte.length);
                String requestId = header.getRequestId();
                CompletableFuture<String> res = new CompletableFuture<>();
                ResponseMappingCallback.addCallback(requestId,res);

                buf.writeBytes(packageMsgByte);
                ChannelFuture future = client.writeAndFlush(buf);
                future.sync();
                return res.get();
            }
        });
    }

    private static MyHeader convertHeader(byte[] msgBody) {
        int length = msgBody.length;
        MyHeader header = new MyHeader();
        header.setFlag(0x14141414);
        header.setRequestId(UUID.randomUUID().toString().replaceAll("-", ""));
        header.setDataLen(length);
        return header;
    }

    private static <T> MyContent convertContent(Class<T> clazz, Method method, Object[] args) {
        String className = clazz.getName();
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();

        MyContent content = new MyContent();
        content.setInterfaceName(className);
        content.setMethodName(methodName);
        content.setParameterTypes(parameterTypes);
        content.setArgs(args);
        return content;
    }
}